package com.mxchip.livestar.av.player;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLSurfaceView;
import android.util.Log;

import com.mxchip.livestar.av.camera.CameraHandle;
import com.mxchip.livestar.av.camera.HDMIHandle;
import com.mxchip.livestar.av.camera.WifiCamera;
import com.mxchip.livestar.av.screen.DecoderScreen;
import com.mxchip.livestar.av.screen.PreviewScreen;
import com.mxchip.livestar.av.screen.Screen;
import com.mxchip.livestar.av.screen.ScreenSettings;
import com.mxchip.livestar.utils.FileLog;
import com.mxchip.livestar.utils.MyLog;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * 视频渲染类
 */
public class HxbSurfaceRender implements GLSurfaceView.Renderer {

    private static final String TAG = "HxbSurfaceRender";
    // private CameraTouchControl control;
    private Context context;
    private int width;
    private int height;
    private static final FileLog logger = FileLog.getLogger(HxbSurfaceRender.class);

    private ScreenSettings screenSettings;

    private Map<Screen, AbsSubRenderer> workingSubRenderers = Collections.synchronizedMap(new LinkedHashMap<>());

    private final Set<AbsSubRenderer> idleSubRenderers = Collections.synchronizedSet(new HashSet<>());
    private final Set<AbsSubRenderer> allSubRenderers = Collections.synchronizedSet(new HashSet<>());

    public HxbSurfaceRender(Context context) {
        this.context = context;
        // this.onSurfaceCreatedListener = onSurfaceCreatedListener;
//        control = new CameraTouchControl(view);
//        control.setVideoGestureListener(videoGestureListener);
        initSubRenderers();
    }

    /**
     * 视频窗口排列,确定工作窗口和空闲窗口
     * @param screenSettings
     */
    public synchronized void setScreenSettings(ScreenSettings screenSettings) {

        Log.e("ScreenViewModel", "setScreenSettings " + screenSettings);

        this.screenSettings = screenSettings;

        if (this.screenSettings == null) {
            workingSubRenderers.clear();
            idleSubRenderers.clear();

            allSubRenderers.forEach(renderer -> {
                if (renderer != null && renderer.getOnSurfaceCreatedHandler() instanceof DecoderHandler) {
                    DecoderHandler decoderHandler = (DecoderHandler) renderer.getOnSurfaceCreatedHandler();
                    decoderHandler.setName(null);
                    decoderHandler.stopDecoder();

                    renderer.clearSurfaceTexture();
                }
            });

            idleSubRenderers.addAll(allSubRenderers);
            return;
        }

        Screen[] allScreen = this.screenSettings.getAllScreens();

        ArrayList<Screen> newlyScreens = new ArrayList<Screen>(Arrays.asList(allScreen));

        List<Screen> unusedScreens = workingSubRenderers.keySet().stream().filter(screen -> {
            // boolean hit = false;
            Screen hitScreen = null;

            for (Screen s : newlyScreens) {
                if (s != null && s.equals(screen)) {
                    hitScreen = s;
                    break;
                }
            }

            if (hitScreen != null) {
                newlyScreens.remove(hitScreen);
            }

            return hitScreen == null;
        }).collect(Collectors.toList());

        unusedScreens.forEach(screen -> {
            AbsSubRenderer renderer = workingSubRenderers.remove(screen);

            if (renderer != null && renderer.getOnSurfaceCreatedHandler() instanceof DecoderHandler) {
                DecoderHandler decoderHandler = (DecoderHandler) renderer.getOnSurfaceCreatedHandler();
                decoderHandler.setName(null);
                decoderHandler.stopDecoder();

                // renderer.clearSurfaceTexture();
            }

            idleSubRenderers.add(renderer);
        });


        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: screenSettings " + screenSettings);
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: unusedScreens " + unusedScreens);
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: newlyScreens " + newlyScreens);

        for (Screen screen : newlyScreens) {

            MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: newlyScreen " + screen);

            if (screen instanceof PreviewScreen) {

                PreviewScreen previewScreen = (PreviewScreen) screen;
                List<AbsSubRenderer> items = null;

                if (previewScreen.type == PreviewScreen.Type.FrontCamera) {
                    items = idleSubRenderers.stream().filter(subRenderer -> subRenderer.getOnSurfaceCreatedHandler() instanceof CameraHandle).collect(Collectors.toList());
                }
                if (previewScreen.type == PreviewScreen.Type.HDMICamera) {
                    items = idleSubRenderers.stream().filter(subRenderer -> subRenderer.getOnSurfaceCreatedHandler() instanceof HDMIHandle).collect(Collectors.toList());
                }
                if (previewScreen.type == PreviewScreen.Type.WIFICamera) {
                    items = idleSubRenderers.stream().filter(subRenderer -> subRenderer.getOnSurfaceCreatedHandler() instanceof WifiCamera).collect(Collectors.toList());
                }

                if (items != null && items.size() > 0) {
                    AbsSubRenderer item = items.get(0);

                    if (item != null) {
                        idleSubRenderers.remove(item);
                        workingSubRenderers.put(screen, item);
                    }
                }
            } else if (screen instanceof DecoderScreen) {

                // MyLog.logTime("HxbSurfaceRender:setScreenSettings: screen " + screen);

                DecoderScreen decoderScreen = (DecoderScreen) screen;

                String decoderName = decoderScreen.decoderName;

                List<AbsSubRenderer> items = null;

                items = idleSubRenderers.stream().filter(subRenderer -> subRenderer.getOnSurfaceCreatedHandler() instanceof DecoderHandler).collect(Collectors.toList());

                MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: DecoderScreen " + items);

                if (items != null && items.size() > 0) {

                    AbsSubRenderer item = items.get(0);

                    idleSubRenderers.remove(item);

                    if (item.getOnSurfaceCreatedHandler() instanceof DecoderHandler) {
                        DecoderHandler decoderHandler = (DecoderHandler) item.getOnSurfaceCreatedHandler();

                        decoderHandler.initDecoder(decoderScreen.getDecoderMimeType(), decoderScreen.getDecodeWidth(), decoderScreen.getDecodeHeight());
                        decoderHandler.setName(decoderName);


//                        if(!decoderHandler.isMediaCodecStart()) {
//                            decoderHandler.startDecoder();
//                        }
                    }

                    workingSubRenderers.put(screen, item);
                }
            }
        }
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: Thread.currentThread() " + Thread.currentThread());
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: workingSubRenderers " + workingSubRenderers);
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: requestRenderInvoke " + requestRenderInvoke);
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:setScreenSettings: CameraHandle.getInstance().isCameraOpen " + CameraHandle.getInstance().isCameraOpen());

        /*if (requestRenderInvoke != null) {
            requestRenderInvoke.invokeRequestRender();
        }*/

    }

    /**
     * 初始化渲染窗
     */
    private void initSubRenderers() {
        // RenderDisplay.getInstance().init();

        // index0 localCamera
        // 前置摄像头
        createRender(CameraHandle.getInstance());
        //index1 RemoteCamera
        createRender(new DecoderHandler());
        //index2
        createRender(new DecoderHandler());
        //index3
        createRender(new DecoderHandler());
        //index4
        createRender(new DecoderHandler());
        //index5 HDMI

        // HDMI摄像头
        createRender(HDMIHandle.getInstance());
        //index6 HDMIRemote
        createRender(new DecoderHandler());

        // WIFI Camera
        createRender(WifiCamera.getInstance());
    }

    /**
     * 创建各个窗口的渲染器
     * @param onSurfaceCreatedHandler
     */
    private void createRender(OnSurfaceCreatedHandler onSurfaceCreatedHandler) {

        // MyLog.logTime("HxbSurfaceRender:createRender: index: " + index);

        AbsSubRenderer renderer = new SubRenderer(context);

        /*if(onSurfaceCreatedHandler instanceof CameraPreviewOnSurfaceCreatedHandler) {
            renderer = new SubRenderer(view.getContext());
        } else if(onSurfaceCreatedHandler instanceof DecoderOnSurfaceCreatedHandler) {
            renderer = new DecoderSubRenderer(view.getContext());
        }

        if(renderer == null) {
            return;
        }*/

        renderer.setOnSurfaceCreatedHandler(onSurfaceCreatedHandler);
        renderer.setOnRenderListener(() -> {
            if (requestRenderInvoke != null) {
                requestRenderInvoke.invokeRequestRender();
            }
        });

        // RendererDataInfo renderDataInfo = RenderDisplay.getInstance().getRenderDataInfos()[index];

        // MyLog.logTime("HxbSurfaceRender:createCameraRender: createRender: " + renderDataInfo);

        // renderDataInfo.setWindowPosition(index);
        // renderDataInfo.setSubRenderer(renderer);

        idleSubRenderers.add(renderer);
        allSubRenderers.add(renderer);
    }

    /**
     * 视频窗口创建时,初始化摄像头/解码器资源
     * @param gl
     * @param config
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:onSurfaceCreated: ");

        for (AbsSubRenderer renderer : allSubRenderers) {
            renderer.onSurfaceCreated(gl, config);

            OnSurfaceCreatedHandler handler = renderer.getOnSurfaceCreatedHandler();
            SurfaceTexture surfaceTexture = renderer.getSurfaceTexture();

            if (handler instanceof PreviewOnSurfaceCreatedHandler) {
                PreviewOnSurfaceCreatedHandler cameraPreviewHandler = (PreviewOnSurfaceCreatedHandler) handler;

                new Thread(() -> {
                    Log.e(TAG, "Thread.currentThread(): " + Thread.currentThread());
                    if (cameraPreviewHandler instanceof WifiCamera) {
                        // WIFI Camera
                        WifiCamera.getInstance().setDecodeTexture(surfaceTexture);
                    } else if (cameraPreviewHandler instanceof HDMIHandle) {
                        // HDMI摄像头
                        boolean hdmiOpenState = HDMIHandle.getInstance().openCamera();
                        if (hdmiOpenState) {
                            HDMIHandle.getInstance().setPreviewTexture(surfaceTexture);
                        } else {
                            logger.info(new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(new Date()) + "HDMI Camera open failed hangup");
                            // RoomClientRepository.INSTANCE.hangup();
                            // SystemData.getInstance().sm_evthandle(Event.hungupBtnClick);
                        }

                    } else if (cameraPreviewHandler instanceof CameraHandle) {
                        // 前置摄像头

                        CameraHandle.getInstance().openAndStartPreview(surfaceTexture);

                        /*boolean cameraOpenState = CameraHandle.getInstance().openCamera();
                        CameraHandle.getInstance().initEncoder();

                        Log.e("HxbSurfaceRender", "cameraOpenState: " + cameraOpenState + ", surfaceTexture " + surfaceTexture);
                        if (cameraOpenState) {
                            CameraHandle.getInstance().setPreviewTexture(surfaceTexture);
                        } else {
                            logger.info(new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(new Date()) + " Camera open failed hangup");

                            // RoomClientRepository.INSTANCE.hangup();
                            //SystemData.getInstance().sm_evthandle(Event.hungupBtnClick);
                        }*/
                    }

                }).start();

            } else if (handler instanceof DecoderOnSurfaceCreatedHandler) {
                new Thread(() -> {
                    // renderDataInfo.setDecodeIndex(renderIndex > 5 ? renderIndex - 2 : renderIndex - 1);
                    // renderDataInfo.setSurface(surface);
                    // initMediaCodec(1280, 720, surfaceTexture, rendererDataInfo);

                    if (handler instanceof DecoderHandler) {
                        try {
                            // String mime = "video/avc";

                            DecoderHandler decoderHandler = (DecoderHandler) handler;

                            // decoderHandler.initDecoder(mime, 1280, 720);
                            decoderHandler.setSurfaceTexture(surfaceTexture);
                            // decoderHandler.startDecoder();

                            // rendererDataInfo.setDecode(decoderHandler);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }

        // if (onSurfaceCreatedListener != null) {
            // onSurfaceCreatedListener.onSurfaceCreated();
        // }
        MyLog.logD(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender::onSurfaceCreated:finish  NativeFuc."+System.currentTimeMillis());
    }

    /**
     * 视频窗口改变时,获取宽高
     * @param gl
     * @param width
     * @param height
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        MyLog.logTime(MyLog.VIDEO_RENDER_MODEL,"HxbSurfaceRender:onSurfaceChanged: " + width + ", " + height);
        this.width = width;
        this.height = height;

        for (AbsSubRenderer renderer : allSubRenderers) {
            renderer.onSurfaceChanged(gl, width, height);
        }
    }


    /**
     * 根据矩阵位置渲染各个窗口
     * @param gl
     */
    private synchronized void mOnDrawFrame(GL10 gl) {

        if (this.screenSettings != null) {
            List<Screen> zScreens = this.screenSettings.zOrderScreens();

            for (int i = 0; i < zScreens.size(); i++) {

                Screen screen = zScreens.get(i);

                if (screen == null) {
                    continue;
                }

                AbsSubRenderer renderer = workingSubRenderers.get(screen);

                if (this.screenSettings == null || renderer == null) {
                    Log.e("HxbSurfaceRender", "onDrawFrame null renderer " + Thread.currentThread());
                    continue;
                }

                float[] matrix = this.screenSettings.getMatrixByScreen(screen, width, height);

                // MyLog.logTime("HxbSurfaceRender:onDrawFrame: screen: " + screen + " matrix " + Arrays.toString(matrix));

                // renderer.getSurfaceTexture()

                renderer.setMatrix(matrix);
                renderer.onDrawFrame(gl);
            }
        }
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        // MyLog.logTime("HxbSurfaceRender:onDrawFrame: workingSubRenderers " + workingSubRenderers);

        // List<Screen> screens = new ArrayList<>(workingSubRenderers.keySet());

        mOnDrawFrame(gl);
    }


    /**
     * 释放各个解码器
     */
    public void release() {

        if (requestRenderInvoke != null) {
            requestRenderInvoke = null;
        }

        /*if (onSurfaceCreatedListener != null) {
            onSurfaceCreatedListener = null;
        }*/

        /*if (control != null) {
            control.release();
            control = null;
        }*/

        if (context != null) {
            context = null;
        }

        for (AbsSubRenderer renderer : allSubRenderers) {
            if (renderer != null) {
                renderer.release();
                // renderDataInfo.setSubRenderer(null);

                OnSurfaceCreatedHandler handler = renderer.getOnSurfaceCreatedHandler();

                if (handler instanceof DecoderOnSurfaceCreatedHandler) {
                    if (handler instanceof DecoderHandler) {
                        DecoderHandler decoderHandler = (DecoderHandler) handler;
                        decoderHandler.releaseDecoder();
                    }
                }

            }
        }
        // RenderDisplay.getInstance().release();

        // clearStreamNameMap();
    }

    /**
     * 开启HDMI屏幕共享
     */
    public void startResourcePub() {
        HDMIHandle.getInstance().startPreview();
    }

    /**
     * 停止HDMI屏幕共享
     */
    public void stopResourcePub() {
        HDMIHandle.getInstance().stopPreview();
    }

    /**
     * 开启无线投屏屏幕共享
     */
    public void startWifiResourcePub() {
        logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date()) +
                "HxbSurfaceRender::" + "send wifi  step 1 ");
        // int mVideoId = 0;
        // WifiCamera.getInstance().open(mVideoId);
        // WifiCamera.getInstance().configure(width, height);
        // mNativeWifiCamera.setEncoderCallback(mEncoderCallback);
        WifiCamera.getInstance().start();
    }

    /**
     * 关闭无线投屏屏幕共享
     */
    public void stopWifiResourcePub() {
        logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date()) +
                "HxbSurfaceRender::" + "send wifi  step 3 ");
        WifiCamera.getInstance().stop();
    }



    /**
     * RequestRender
     */
    private RequestRenderInvoke requestRenderInvoke;

    public void setRequestRenderInvoke(RequestRenderInvoke requestRenderInvoke) {
        this.requestRenderInvoke = requestRenderInvoke;
    }


    public interface RequestRenderInvoke {
        void invokeRequestRender();
    }

    /**
     * ResourcesListener
     */
    // private OnSurfaceCreatedListener onSurfaceCreatedListener;

    /**
     * 解码视频数据
     * @param dataSize 视频数据大小
     * @param data 视频数据
     * @param decoderName 视频对应的user,即获取响应的解码器
     */
    public void decodeAVPacket(int dataSize, byte[] data, String decoderName) {

        long timeMillis = System.currentTimeMillis();
        // MyLog.logD("HxbPlayer::" + "decodeAVPacket decoderName: " + decoderName + ", dataSize: " + dataSize + ", data: " + data);

        if ((dataSize < 0 && data == null)) {
            return;
        }

        List<Screen> screens = new ArrayList<>(workingSubRenderers.keySet());

        // MyLog.logD("HxbPlayer::" + "decodeAVPacket workingSubRenderers: " + workingSubRenderers);
        // MyLog.logD("HxbPlayer::" + "decodeAVPacket workingSubRenderers screens: " + screens);

        for (Screen screen : screens) {

            AbsSubRenderer renderer = workingSubRenderers.get(screen);

            // MyLog.logD("HxbPlayer::" + "decodeAVPacket renderer: " + renderer);

            if (renderer == null) {
                break;
            }

            OnSurfaceCreatedHandler handler = renderer.getOnSurfaceCreatedHandler();

            // MyLog.logD("HxbPlayer::" + "decodeAVPacket handler: " + handler);
            // MyLog.logD("HxbPlayer::" + "decodeAVPacket handler instanceof DecodeHandler: " + (handler instanceof DecoderHandler));

            if (handler instanceof DecoderHandler) {
                // MyLog.logD("HxbPlayer::" + "decodeAVPacket handler instanceof ((DecodeHandler) handler).name: " + ((DecoderHandler) handler).getName());
            }

            if (handler instanceof DecoderHandler && ((DecoderHandler) handler).getName().equals(decoderName)) {

                // MyLog.logD("HxbPlayer::" + "decodeAVPacket putData: " + Arrays.toString(data));

                DecoderHandler decoderHandler = ((DecoderHandler) handler);

                if (!decoderHandler.isMediaCodecStart()) {
                    decoderHandler.startDecoder();
                }

                // MyLog.logD("HxbPlayer::" + "decodeAVPacket decoderHandler.isMediaCodecStart: " + decoderHandler.isMediaCodecStart());

                decoderHandler.putData(data,decoderName);
            }

        }

    }

}
